﻿using System;
using System.Collections.Concurrent;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using DL.PhotoCollage.Core;
using DL.PhotoCollage.Wpf.UserControls;

namespace DL.PhotoCollage.Wpf.Presentation
{
    public abstract class CollagePresenterBase
    {
        protected CollagePresenterBase(ControllerBase controller)
        {
            this.Controller = controller;
            this.PhotoRespository = this.GetPhotoRepository();
            this.ImageQueue = new ConcurrentQueue<ImageDisplayUserControl>();
            this.MaxInQueue = this.Controller.Configuration.NumberOfPhotos;
        }

        protected ControllerBase Controller { get; set; }

        protected IPhotoRepository PhotoRespository { get; private set; }

        protected int MaxInQueue { get; private set; }

        protected ConcurrentQueue<ImageDisplayUserControl> ImageQueue { get; private set; }

        protected Window ViewWindow { get; set; }

        protected Canvas ViewCanvas { get; set; }

        public void StartAnimation()
        {
            try
            {
                if (!this.PhotoRespository.HasPhotos)
                {
                    this.Controller.DisplayErrorMessage("Folder does not contain any supported photos.");
                    this.Controller.ShutdownApplication();
                }

                this.DisplayImageTimerTick(null, null);

                int seconds = (int)this.Controller.Configuration.Speed;
                var timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, seconds) };
                timer.Tick += this.DisplayImageTimerTick;
                timer.Start();
            }
            catch (Exception ex)
            {
                this.Controller.HandleError(ex);
            }
        }       

        protected void AddControlToView(ImageDisplayUserControl control)
        {
            this.ViewCanvas.Children.Add(control);
        }

        protected bool DoesViewContainControl(ImageDisplayUserControl control)
        {
            return this.ViewCanvas.Children.Contains(control);
        }

        protected double GetViewActualHeight()
        {
            return this.ViewWindow.ActualHeight;
        }

        protected double GetViewActualWidth()
        {
            return this.ViewWindow.ActualWidth;
        }

        protected void RemoveControlFromView(ImageDisplayUserControl control)
        {
            this.ViewCanvas.Children.Remove(control);
        }

        private IPhotoRepository GetPhotoRepository()
        {
            if (this.Controller.Configuration.IsRandom)
            {
                return new RandomFileSystemPhotoRepository(this.Controller.Configuration.Directory);
            }

            return new OrderedFileSystemPhotoRepository(this.Controller.Configuration.Directory);
        }

        private void DisplayImageTimerTick(object sender, EventArgs e)
        {
            try
            {
                string path = this.PhotoRespository.NextPhotoFilePath;

                var control = new ImageDisplayUserControl(this.Controller, path);
                this.AddControlToView(control);
                this.ImageQueue.Enqueue(control);

                if (this.ImageQueue.Count > this.MaxInQueue)
                {
                    this.RemoveImageFromQueue();
                }

                this.SetUserControlPosition(control);
            }
            catch (Exception ex)
            {
                this.Controller.HandleError(ex);
                this.Controller.ShutdownApplication();
            }
        }

        private void SetUserControlPosition(UIElement control)
        {
            double viewportWidth = this.GetViewActualWidth();
            double viewportHeight = this.GetViewActualHeight();

            var positioner = new ImagePositioner(this.Controller, control, viewportWidth, viewportHeight);
            positioner.Position();
        }

        private void RemoveImageFromQueue()
        {
            ImageDisplayUserControl control;

            if (this.ImageQueue.TryDequeue(out control))
            {
                Action<ImageDisplayUserControl> action = this.RemoveImageFromPanel;
                control.FadeOutImage(action);
            }
        }

        private void RemoveImageFromPanel(ImageDisplayUserControl control)
        {
            try
            {
                if (this.DoesViewContainControl(control))
                {
                    this.RemoveControlFromView(control);
                }
            }
            catch (Exception ex)
            {
                this.Controller.HandleError(ex);
            }
        }
    }
}
